In [1]:
%pylab inline
from scipy.integrate import simps
In [2]:
import pyximport; pyximport.install(setup_args={"include_dirs":numpy.get_include()})
import paramless as pmain
import paramless_cython as pm
In [3]:
from JSAnimation.IPython_display import display_animation
Here I test the function simulation framework with the example of section 6 in Dieckmann et al. JTB (2006)
We will evolve a function $x(a)$, where $a \in [0,1]$ (s.t $x(a) > 0 \forall a$ )
The domain of $x(\cdot)$ is $(0,1)$.
In [4]:
domain = np.arange(0.001, 1.0, 0.01)
Set up the fitness class
In [5]:
class MetabolicFitness(pm.FitnessFunction):
def __init__(self, c, domain):
self.c = c
self.domain = domain
def get(self, resident, mutant):
pass
The energy is defined as $E(x) = \int x(a) da$, which for simulation purposes we will compute using simpson's.
In [6]:
def energy(self, surface, domain):
return simps(surface, domain)
MetabolicFitness.energy = energy
Metabolic efficiency is defined as $e(a, x(a)) = \frac{x(a)}{x(a)+a}$. Then, the total intake of resources is given by $G(x) = \int r(a)e(a, (a)) da$
In [7]:
def resource_density(self, a):
return 4.0 * (1.0 - a)
def total_intake(self, surface, domain):
#create a list of pairs x(a) = a for a in domain
tuples_surface_domain = zip(surface, domain)
#r(a)*(x(a)/x(a)+a) for all a in domain
integrand = [self.resource_density(surface_domain[1])*(surface_domain[0]/(surface_domain[0]+surface_domain[1])) for surface_domain in tuples_surface_domain]
#integrate over domain
return simps(integrand, domain)
MetabolicFitness.resource_density = resource_density
MetabolicFitness.total_intake = total_intake
With the total intake and the energy we are ready to compute fitness.
In [8]:
def metabolic_fitness(self,resident, mutant = None):
fitness_resident = self.total_intake(resident, domain) - self.c*self.energy(resident, domain)
if not mutant is None:
fitness_mutant = self.total_intake(mutant, domain) - self.c*self.energy(mutant, domain)
return fitness_resident, fitness_mutant
else:
return fitness_resident
MetabolicFitness.get = metabolic_fitness
We use the point mutation that does not allow for negative values and conserves energy.
In [9]:
number_of_generations=5000
initial_surface = np.zeros_like(domain)
In [10]:
fitness_function = MetabolicFitness(0.5,domain)
mutator = pm.GaussianMutator(0.01,domain,0.02,0.0)
evolver = pm.StandardEvolver(fitness_function,mutator,1e-8)
ans, series = pmain.evolve(initial_surface, evolver,
iterations=number_of_generations,
return_time_series=True)
In [11]:
plot(domain, ans)
Out[11]:
In [12]:
def prediction_investment(a):
c=0.5
if resource_density(None,a) > 0.5*a:
return math.sqrt((a/c)*resource_density(None,a))-a
return 0.0
In [13]:
target = [prediction_investment(a) for a in domain]
In [14]:
plot(domain, target)
plot(domain, ans)
Out[14]:
In [15]:
ani = pmain.create_video_from_time_series(series, target, domain, filename='./metabolic_soft.mp4', approximate_number_of_frames=300, record_every=50)
display_animation(ani)
Out[15]:
In [16]:
number_of_generations=50000
mutator = pm.PointMutator(0.01,0.0)
evolver = pm.StandardEvolver(fitness_function,mutator,1e-8)
ans_stiff, series_stiff = pmain.evolve(initial_surface, evolver,
iterations=number_of_generations,
return_time_series=True)
In [17]:
plot(domain, target)
plot(domain, ans_stiff)
Out[17]:
In [18]:
ani_stiff = pmain.create_video_from_time_series(series_stiff, target, domain, filename='./metabolic_hard.mp4', approximate_number_of_frames=100, record_every=1000)
display_animation(ani_stiff)
Out[18]:
In [ ]: